#include"Engine.h"

namespace Advanced2D{
	Engine::Engine(){
		srand( (unsigned int)time(NULL) );
		p_windowHandle = NULL;
		p_fullscreen = false;
		p_apptitle = "Advanced2D";
		p_screenwidth = 800;
		p_screenheight = 600;		
	}

	Engine::~Engine(){
		if(p_device){
			p_device->Release();
		}
		if(p_d3d){
			p_d3d->Release();
		}
				
		if(p_input) delete p_input;
	}	

	bool Engine::Init(int width, int height, int colordepth, bool fullscreen){
		//Khoi tao Direct3D
		p_d3d = (LPDIRECT3D9)Direct3DCreate9(D3D_SDK_VERSION);
		if(!p_d3d){
			return false;
		}

		//lay he thong do sau mau cua desktop
		D3DDISPLAYMODE dm;
		p_d3d->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &dm );

		//cai dat Direct3D
		D3DPRESENT_PARAMETERS d3dpp;
		ZeroMemory(&d3dpp, sizeof(d3dpp));

		d3dpp.Windowed = (!fullscreen);
		d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
		d3dpp.EnableAutoDepthStencil = TRUE;
		d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
		d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
		d3dpp.BackBufferFormat = dm.Format;
		d3dpp.BackBufferCount = 1;
		d3dpp.BackBufferWidth = width;
		d3dpp.BackBufferHeight = height;
		d3dpp.hDeviceWindow = p_windowHandle;

		//khoi dao phuong thuoc Direct3D
		p_d3d->CreateDevice( D3DADAPTER_DEFAULT, 
							 D3DDEVTYPE_HAL, 
							 p_windowHandle, 
							 D3DCREATE_HARDWARE_VERTEXPROCESSING, 
							 &d3dpp, 
							 &p_device );
		if(!p_device){
			return false;
		}

		//lam sach backbuffer bang mau den
		ClearScene(D3DCOLOR_XRGB(0, 0, 0));

		//khoi tao con tro backbuffer
		p_device->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &p_backbuffer);	

		//khoi tao sprite handler
		HRESULT result = D3DXCreateSprite( p_device, &p_spritehandler);
		if(result != D3D_OK){
			return false;
		}

		//khoi tao input
		p_input = new Input(getWindowHandle());						

		if(!game_init()){
			return false;
		}

		return true;
	}

	void Engine::Update(){
		static Timer timeUpdate;
		
		game_update();

		UpdateEntities();

		if(!timeUpdate.stopwatch(14))
			Sleep(1);
		else{
			//cap nhat ban phiem
			p_input->Update();
			UpdateKeyboard();
			
			//lam sach backbuffer bang mau den
			ClearScene(D3DCOLOR_XRGB(0, 0, 0));

			//Bat dau ve
			if(!p_device) return;
			if(p_device->BeginScene() != D3D_OK) return;

			//Cai dat the hien 2D
			if(p_spritehandler->Begin(D3DXSPRITE_ALPHABLEND) != D3D_OK) return;
			
			//The hien sprite 2D
			game_render2D();

			DrawEntities();

			//Ket thuc the thien 2D
			if(p_spritehandler->End() != D3D_OK) return;

			//Ket thu ve
			if(!p_device) return;
			if(p_device->EndScene() != D3D_OK) return;
			if(p_device->Present(NULL, NULL, NULL, NULL) != D3D_OK) return;
		}

		DeleteEntities();
	}

	void Engine::Close(){
		game_end();
	}

	void Engine::ClearScene(D3DCOLOR color){
		p_device->Clear(0, NULL, D3DCLEAR_TARGET| D3DCLEAR_ZBUFFER, color, 1.0f, 0);
	}

	void Engine::ExitGame(){
		game_over = true;
	}

	void Engine::UpdateKeyboard(){
		static char old_keys[256];
		for(int i = 0; i < 255; i++){
			if(p_input->GetKeyState(i) & 0x80 ){
				game_keyPress(i);
				old_keys[i] = p_input->GetKeyState(i);
			}
			else{
				if( old_keys[i] & 0x80 ){
					game_keyRelease(i);
					old_keys[i] = p_input->GetKeyState(i);
				}
			}
		}
	}

	void Engine::UpdateEntities(){
		std::list<Entity*>::iterator iter = p_entities.begin();
		Entity* entity;

		while(iter != p_entities.end()){
			//tao do cua sprite trong danh sach;
			entity = *iter;

			if(entity->getAlive()){
				entity->move();
				entity->animate();
				
				game_entityUpdate(entity);

				//Kiem tra xem phan tu het thoi gian song chua
				if(entity->getLifeTimeLength() > 0){
					if(entity->lifetimeExpried()){
						entity->setAlive(false);
					}
				}
			}
			++iter;
		}
	}

	void Engine::DrawEntities(){
		std::list<Entity*>::iterator iter = p_entities.begin();
		Entity* entity;
		
		while(iter != p_entities.end()){			
			entity = *iter;
			
			if(entity->getAlive() && entity->getVisible()){
				entity->draw();

				game_entityRender(entity);
			}
			iter++;
		}
	}

	void Engine::DeleteEntities(){
		std::list<Entity*>::iterator iter = p_entities.begin();

		while(iter != p_entities.end()){
			if((*iter)->getAlive() == false){
				iter = p_entities.erase(iter);
			}
			else iter++;
		}
	}

	void Engine::addEntity(Entity* entity){
		p_entities.push_back(entity);
	}

	Entity* Engine::findEntity(int objectType){
		std::list<Entity*>::iterator iter = p_entities.begin();

		while(iter != p_entities.end()){
			if((*iter)->getAlive() == true && (*iter)->getObjectType() == objectType){
				return *iter;
			}
			else iter++;
		}
		return NULL;
	}
}